from machine import Pin, reset
import network
import socket
import camera
import time
import gc
import _thread
import usocket as usocket

# ==================== 配置参数 ====================
WIFI_SSID = "LAPTOP-D3RPTUAA 6358"
WIFI_PASSWORD = "19234949992.ch"
ESP32_S3_IP = "192.168.137.100"  # S3的IP
ESP32_S3_UDP_PORT = 5000        # S3的UDP端口

# 图像参数（确保10帧/秒）
CAM_RESOLUTION = 8                      # 320x240
CAM_QUALITY = 30                        # 略降低质量，减少数据量
TARGET_FPS = 10                         # 目标帧率
FRAME_INTERVAL = 1 / TARGET_FPS         # 帧间隔

# ==================== 全局变量 ====================
latest_frame = None
frame_lock = _thread.allocate_lock()
udp_socket = usocket.socket(usocket.AF_INET, usocket.SOCK_DGRAM)

# ==================== 初始化 ====================
def init_wifi():
    wlan = network.WLAN(network.STA_IF)
    wlan.active(True)
    wlan.connect(WIFI_SSID, WIFI_PASSWORD)
    for _ in range(30):
        if wlan.isconnected():
            ip = wlan.ifconfig()[0]
            print(f"WiFi已连，IP: {ip}")
            return ip
    reset()

def init_camera():
    try:
        camera.init()
        camera.framesize(CAM_RESOLUTION)
        camera.quality(CAM_QUALITY)
        camera.flip(1)  # 根据硬件调整
        print(f"摄像头初始化完成（目标帧率: {TARGET_FPS}帧/秒）")
        return True
    except Exception as e:
        print(f"摄像头错误: {e}")
        return False

# ==================== 图像捕获线程（确保10帧/秒） ====================
def capture_thread():
    global latest_frame
    last_time = time.ticks_ms()
    while True:
        # 控制帧率：确保每FRAME_INTERVAL秒捕获一帧
        current_time = time.ticks_ms()
        elapsed = time.ticks_diff(current_time, last_time) / 1000
        if elapsed < FRAME_INTERVAL:
            time.sleep(FRAME_INTERVAL - elapsed)  # 精确等待
        
        try:
            frame = camera.capture()  # 硬件编码，耗时<50ms
            if frame:
                with frame_lock:
                    latest_frame = frame
            last_time = current_time
        except Exception as e:
            print(f"捕获错误: {e}")
            camera.deinit()
            time.sleep(1)
            init_camera()
        gc.collect()

# ==================== UDP发送小数据（给S3） ====================
def send_to_s3(data):
    """发送小数据（字符串格式，如"cmd:start"、"temp:25"）"""
    try:
        udp_socket.sendto(data.encode(), (ESP32_S3_IP, ESP32_S3_UDP_PORT))
        # 调试用：print(f"发送到S3: {data}")
    except Exception as e:
        print(f"UDP发送失败: {e}")

# ==================== HTML服务器（含数据交互） ====================
def handle_client(client_sock):
    try:
        req = client_sock.recv(1024).decode()
        path = req.split(' ')[1]

        # 1. 主页：实时画面 + 数据输入框
        if path == '/':
            html = """

                    <!DOCTYPE html>
                    <html>
                    <head>
                        <title>cam</title>
                        <meta name="viewport" content="width=device-width, initial-scale=1.0">
                    </head>
                    <body>
                        <img src="/stream" style="width:100%;">
                    </body>
                    </html>
                    
                    """
            
            res = f"HTTP/1.1 200 OK\r\nContent-Length: {len(html)}\r\n\r\n{html}"
            client_sock.send(res.encode())

        # 2. 处理数据发送请求
        elif path.startswith('/send'):
            data = path.split('=')[1] if '=' in path else ""
            send_to_s3(data)  # 调用UDP发送
            res = "HTTP/1.1 200 OK\r\nContent-Length: 10\r\n\r\n发送成功"
            client_sock.send(res.encode())

        # 3. MJPEG流（10帧/秒）
        elif path == '/stream':
            header = (
                b"HTTP/1.1 200 OK\r\n"
                b"Content-Type: multipart/x-mixed-replace; boundary=frame\r\n"
                b"\r\n"
            )
            client_sock.send(header)
            while True:
                with frame_lock:
                    if not latest_frame:
                        time.sleep(0.01)
                        continue
                    frame = latest_frame
                # 快速封装MJPEG帧（减少CPU耗时）
                part = (
                    b"--frame\r\n"
                    b"Content-Type: image/jpeg\r\n"
                    b"Content-Length: %d\r\n"
                    b"\r\n"
                    % len(frame)
                ) + frame
                client_sock.send(part)
                time.sleep(FRAME_INTERVAL - 0.01)  # 配合捕获线程控制帧率

        # 4. 其他路径
        else:
            client_sock.send(b"HTTP/1.1 404 Not Found\r\n\r\n")

    except Exception as e:
        print(f"HTTP错误: {e}")
    finally:
        client_sock.close()
        gc.collect()

def start_http_server(ip):
    server_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    server_sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    server_sock.bind((ip, 80))
    server_sock.listen(1)
    print(f"访问 http://{ip} 查看画面和发送数据")
    while True:
        client_sock, _ = server_sock.accept()
        handle_client(client_sock)

# ==================== 主程序 ====================
if __name__ == "__main__":
    gc.enable()
    ip = init_wifi()
    if not init_camera():
        reset()
    
    # 启动图像捕获线程（确保10帧/秒）
    _thread.start_new_thread(capture_thread, ())
    # 启动HTTP服务器
    start_http_server(ip)